package com.monster.completable.future;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * description:
 * then系列方法
 * @author Yuanml on 2021/9/19 15:08
 */
public class ThenX {

    private CompletableFuture<String> future1() {
        return CompletableFuture.supplyAsync(() -> {
            System.out.println("future1 start");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("future1 over");
            return "hello,I'm the result of future task 1";
        });
    }



    /**
     * description:
     * 基于thenRun实现异步任务A，执行完后，激活异步任务B
     * 使用thenRun时，后续任务B是拿不到前置任务A的执行结果的
     * thenRun的返回值为null
     * @author Yuanml
     * @date 2021/9/19 15:16
     **/
    public void studyThenRun() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future2 = future1().thenRun(() -> {
            System.out.println("future2 start");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("future2 over");
        });
        System.out.println(future2.get());
    }

    /**
     * description:
     * 基于thenAccept实现异步任务A，执行完毕后，激活异步任务B
     * 使用thenAccept时，后续任务B是可以拿到前置任务A的执行结果的
     * thenAccept的返回值为null
     * @author Yuanml
     * @date 2021/9/19 15:25
     **/
    public void studyThenAccept() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future2 = future1().thenAccept((res) -> {
            System.out.println("future2 start");
            System.out.println("前置任务执行结果：" + res);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("future2 over");
        });
        System.out.println(future2.get());
    }

    /**
     * description:
     * 基于thenApply实现异步任务A，执行完毕后，激活异步任务B
     * 异步任务B可以拿到前置任务A的返回结果，并且任务B可以返回一个结果
     * @author Yuanml
     * @date 2021/9/19 15:33
     **/
    public void studyThenApply() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> future2 = future1().thenApply((res) -> {
            System.out.println("future2 start");
            System.out.println("前置任务执行结果：" + res);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("future2 over");
            return "hello， I'm the result of future task 2";
        });
        System.out.println(future2.get());
    }


    /**
     * description:
     * 基于whenComplete设置回调函数，当异步任务执行完毕后进行回调，不会阻塞调用线程
     * @author Yuanml
     * @date 2021/9/19 15:45
     **/
    public void studyWhenComplete() throws ExecutionException, InterruptedException {
        CompletableFuture<String> whenComplete = future1().whenComplete((str, e) -> {
            if (e == null) {
                System.out.println("future1 run success, result is: " + str);
                return;
            }
            System.out.println("future1 run fail，error message is： " + e.getMessage());
        });
        // 调用此方法将阻塞等待whenComplete任务返回结果
        System.out.println(whenComplete.get());
    }


    /** -------------------------------------------------------异步组合编程------------------------------------------------------------------- */

    public CompletableFuture<String> futureTask1(String appName) {
        return CompletableFuture.supplyAsync(() -> {
            long start = System.currentTimeMillis();
            System.out.println("执行异步任务1");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("异步1任务执行结束，执行耗时：" + (System.currentTimeMillis() - start) + "ms");
            return appName + ":" + "[java:100]";
        });
    }

    public CompletableFuture<String> futureTask2(String preRes) {
        return CompletableFuture.supplyAsync(() -> {
            long start = System.currentTimeMillis();
            System.out.println("执行异步任务2");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("异步2任务执行结束，执行耗时：" + (System.currentTimeMillis() - start) + "ms");
            return preRes + "," + "cpu:0.12";
        });

    }

    public CompletableFuture<String> futureTask3(String preRes) {
        return CompletableFuture.supplyAsync(() -> {
            long start = System.currentTimeMillis();
            System.out.println("执行异步任务3");
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("异步3任务执行结束，执行耗时：" + (System.currentTimeMillis() - start) + "ms");
            return preRes + "," + "memory:3.8G";
        });
    }

    /**
     * description:
     * 组合两个异步任务，a.thenCompose(b) => 当异步任务a执行结束后激活异步任务b进行执行
     * 该方法作用对象为CompletableFuture
     * @author Yuanml
     * @date 2021/9/19 17:52
     **/
    public void studyThenCompose() throws ExecutionException, InterruptedException {
        CompletableFuture<String> stringCompletableFuture = futureTask1("test").thenCompose(this::futureTask2);
        System.out.println(stringCompletableFuture.get());
    }

    /**
     * description:
     * 组合两个异步任务，a.thenCombine(b,(r1,r2) ->{}) => 并行执行a与b，两者执行结束后执行回调函数处理a和b返回的结果
     * @author Yuanml
     * @date 2021/9/19 18:07
     **/
    public void studyThenCombine() throws ExecutionException, InterruptedException {
        CompletableFuture<String> stringCompletableFuture = futureTask1("test").thenCombine(futureTask2("test"), (a, b) -> {
            System.out.println("after future task 1 and future task 2");
            return a + b;
        });
        System.out.println(stringCompletableFuture.get());
    }


    /**
     * description:
     * 组合多个异步任务，CompletableFuture.allOf(a, b, c) => 等待异步任务a、b、c全部完成
     * @author Yuanml
     * @date 2021/9/19 18:12
     **/
    public void studyAllOf() throws ExecutionException, InterruptedException {
        String appName = "test";
        CompletableFuture<Void> future = CompletableFuture.allOf(futureTask1(appName), futureTask2(appName), futureTask3(appName));
        System.out.println(future.get());
    }

    /**
     * description:
     * 组合多个异步任务，CompletableFuture.anyOf(a, b, c) => 等待异步任务a、b、c其中一个完成
     * @author Yuanml
     * @date 2021/9/19 18:12
     **/
    public void studyAnyOf() throws ExecutionException, InterruptedException {
        String appName = "test";
        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(futureTask1(appName), futureTask2(appName), futureTask3(appName));
        System.out.println(objectCompletableFuture.get());
    }
}
